#include<avr/interrupt.h>
#include"buffuart.h"

static unsigned char 			UART0_RxBuf[UART0_RX_BUFFER_SIZE] ;
static unsigned char 			UART0_TxBuf[UART0_TX_BUFFER_SIZE] ;

static unsigned char 			UART1_RxBuf[UART1_RX_BUFFER_SIZE] ;
static unsigned char 			UART1_TxBuf[UART1_TX_BUFFER_SIZE] ;

static volatile unsigned short 	UART_RxHead[2];
static volatile unsigned short 	UART_RxTail[2];

static volatile unsigned short 	UART_TxHead[2];
static volatile unsigned short 	UART_TxTail[2];


void setBaudRate(u8 nUart, u32 baudrate)
{
	// calculate division factor for requested baud rate, and set it
	u16 bauddiv = ((F_CPU+(baudrate*8L))/(baudrate*16L)-1);
	#ifdef TWO_UART
	if(nUart)
	{
		outb(UBRR1L, bauddiv);
		#ifdef UBRR1H
		outb(UBRR1H, bauddiv>>8);
		#endif
	}
	else
	#endif
	{
		outb(UBRR0L, bauddiv);
		#ifdef UBRR0H
		outb(UBRR0H, bauddiv>>8);
		#endif
	}
}


void uart0Init(void)
{
	UART_RxTail[0] = 0;						/* flush the transmit and receive buffers */
	UART_RxHead[0] = 0;
	UART_TxTail[0] = 0;
	UART_TxHead[0] = 0;

    /* set baud rate */
	outp(0, UCSR0B);
    /* enable RxD/TxD and interrupt on character received */
	outp(BV(RXCIE)/*|BV(TXCIE)*/|BV(RXEN)|BV(TXEN), UCSR0B);
	setBaudRate(0, UART0_BAUD_RATE);
  
}

#ifdef TWO_UART
void uart1Init(void)
{
	UART_RxTail[1] = 0;						/* flush the transmit and receive buffers */
	UART_RxHead[1] = 0;
	UART_TxTail[1] = 0;
	UART_TxHead[1] = 0;

	/* set baud rate */
	outp(0, UCSR1B);
    /* enable RxD/TxD and interrupt on character received */
	outp(BV(RXCIE)/*|BV(TXCIE)*/|BV(RXEN)|BV(TXEN), UCSR1B);
	setBaudRate(1, UART1_BAUD_RATE);  
}
#endif


void uart_init( void )
{
	uart0Init();
#ifdef TWO_UART
	uart1Init();
#endif
	return ;
}


void TransmitBytes(u8 nUart,u8* buf, u8 length)
{
    for(u8 i=length; i>0; i--)
	    TransmitByte(nUart, *buf++);
}

void TransmitBytesESC(u8 nUart,u8* buf, u8 length)
{
    for(u8 i=length; i>0; i--)
	{
		u8 ch = *buf++;
		if( (ch==0x7e)||(ch==0x7d) )
		{
			TransmitByte(nUart, 0x7D);
			TransmitByte(nUart, ch^0x20);
		}
		else
		{
			TransmitByte(nUart, ch);
		}
	}
}

#ifndef TWO_UART
#define SIG_UART0_RECV SIG_USART_RECV
#define SIG_UART0_DATA SIG_USART_DATA
#endif

SIGNAL( SIG_UART0_RECV )
{
	unsigned char data;
	unsigned char tmphead;

	data = inp( UDR0 ) ; 							/* read the received data */

	tmphead = (UART_RxHead[0] + 1) ;				/* calculate buffer index */
	tmphead %= UART0_RX_BUFFER_SIZE  ;
	
	UART_RxHead[0] = tmphead; 						/* store new index */

	if ( tmphead == UART_RxTail[0] )
	{
		/* ERROR! Receive buffer overflow */
	}
	UART0_RxBuf[tmphead] = data; /* store received data in buffer */
}

SIGNAL( SIG_UART0_DATA )
{
	unsigned char tmptail;

	/* check if all data is transmitted */
	if ( UART_TxHead[0] != UART_TxTail[0] )
	{
		tmptail = ( UART_TxTail[0] + 1 ) ;		/* calculate buffer index */
		tmptail %= UART0_TX_BUFFER_SIZE ;
		UART_TxTail[0] = tmptail; 				/* store new index */
		outp( UART0_TxBuf[tmptail], UDR0 ) ;	/* start transmition */
	}
	else
	{					/* Buffer Empty - 		*/
		cbi(UCSR0B, UDRIE); 					/* disable UDRE interrupt */
	}
}


#ifdef TWO_UART

SIGNAL(SIG_UART1_RECV)
{
	unsigned char data;
	unsigned char tmphead;

	data = inp( UDR1 ) ; 						/* read the received data */

	
	tmphead = (UART_RxHead[1] + 1) ;			/* calculate buffer index */
	tmphead %= UART1_RX_BUFFER_SIZE  ;
	
	UART_RxHead[1] = tmphead; 					/* store new index */
	
	if ( tmphead == UART_RxTail[1] )
	{
		/* ERROR! Receive buffer overflow */
	}
	UART1_RxBuf[tmphead] = data; /* store received data in buffer */
}

SIGNAL( SIG_UART1_DATA )
{
	unsigned char tmptail;

	/* check if all data is transmitted */
	if ( UART_TxHead[1] != UART_TxTail[1] )
	{
		tmptail = ( UART_TxTail[1] + 1 ) ;		/* calculate buffer index */
		tmptail %= UART1_TX_BUFFER_SIZE ;
		UART_TxTail[1] = tmptail; 				/* store new index */
		outp( UART1_TxBuf[tmptail], UDR1 ) ;	/* start transmition */
	}
	else
	{
										/* Buffer Empty - 		*/
		cbi(UCSR1B, UDRIE); 				/* disable UDRE interrupt */
	}
}

#endif


u8 GetByte( u8 nUart )
{
	unsigned char tmptail;	
	while ( UART_RxHead[nUart] == UART_RxTail[nUart] ) ;/* wait for incomming data */
	
	tmptail = ( UART_RxTail[nUart] + 1 ) ;
	if(nUart)
	{
		tmptail %= UART1_RX_BUFFER_SIZE ;					/* calculate buffer index */
		UART_RxTail[nUart] = tmptail; 						/* store new index */
		return UART1_RxBuf[tmptail]; 						/* return data */
	}
	else
	{
		tmptail %= UART0_RX_BUFFER_SIZE ;					/* calculate buffer index */
		UART_RxTail[nUart] = tmptail; 						/* store new index */
		return UART0_RxBuf[tmptail]; 						/* return data */
	}

}

int ReceiveByte( u8 nUart, u8* ch )
{
	if( UART_RxHead[nUart] != UART_RxTail[nUart] )
	{
		*ch = GetByte(nUart);
		return 1;
	}
	return 0;
}



void TransmitByte(u8 nUart, unsigned char data )
{
	unsigned char tmphead;	
	tmphead = ( UART_TxHead[nUart] + 1 ) ;
		
	#ifdef TWO_UART
	if(nUart)
	{
		tmphead %= UART1_TX_BUFFER_SIZE;		/* calculate buffer index */
	
		// don't wait for space, just exit if buffer full
		//if( tmphead == UART_TxTail )
		//	return;
	
		while ( tmphead == UART_TxTail[1] );	/* wait for free space in buffer */
		cbi(UCSR0B, UDRIE);
		UART1_TxBuf[tmphead] = data; 			/* store data in buffer */
		UART_TxHead[1] = tmphead; 					/* store new index */
		sbi(UCSR1B, UDRIE) ;					/* enable UDRE interrupt */
	}
	else
	#endif
	{
		tmphead %= UART0_TX_BUFFER_SIZE ;		/* calculate buffer index */
	
		// don't wait for space, just exit if buffer full
		//if( tmphead == UART_TxTail )
		//	return;
	
		while ( tmphead == UART_TxTail[0] );		/* wait for free space in buffer */
		cbi(UCSR0B, UDRIE);
		UART0_TxBuf[tmphead] = data; 			/* store data in buffer */
		UART_TxHead[0] = tmphead; 					/* store new index */
		sbi(UCSR0B, UDRIE) ;					/* enable UDRE interrupt */
	}

	return ;
}


u8 DataInReceiveBuffer( u8 nUart )
{
	return ( UART_RxHead[nUart] != UART_RxTail[nUart] ); 	/* return 0 (FALSE) if the receive buffer is empty */
}


